package com.hp_dzzl.utils;

import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.event.entity.player.CriticalHitEvent;
import se.mickelus.mutil.util.CastOptional;
import se.mickelus.tetra.effect.EffectHelper;
import se.mickelus.tetra.effect.ItemEffect;
import se.mickelus.tetra.effect.ItemEffectHandler;

import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
public class Sweeping {
    /**
     * 复制粘贴tetra作者真实横扫的代码
     * 额外增加一个横扫等级的参数来自定义真实横扫的伤害
     */
    public static void truesweep(ItemStack itemStack, LivingEntity attacker, boolean triggerVfx,int damage) {
        float knockback = 0.5f + EnchantmentHelper.getItemEnchantmentLevel(Enchantments.KNOCKBACK, itemStack) * 0.5f;
        double range = 2 + EffectHelper.getEffectEfficiency(itemStack, ItemEffect.sweeping);

        Vec3 target = Vec3.directionFromRotation(attacker.getXRot(), attacker.getYRot())
                .normalize()
                .scale(range)
                .add(attacker.getEyePosition(0));
        AABB aoe = new AABB(target, target);

        // range values set up to mimic vanilla behaviour
        attacker.level().getEntitiesOfClass(LivingEntity.class, aoe.inflate(range, 1d, range)).stream()
                .filter(entity -> entity != attacker)
                .filter(entity -> !attacker.isAlliedTo(entity))
                .forEach(entity -> {
                    entity.knockback(knockback,
                            Mth.sin(attacker.getYRot() * (float) Math.PI / 180F),
                            -Mth.cos(attacker.getXRot() * (float) Math.PI / 180F));

                    ItemEffectHandler.applyHitEffects(itemStack, entity, attacker);
                    EffectHelper.applyEnchantmentHitEffects(itemStack, entity, attacker);


                    DamageSource damageSource = attacker instanceof Player
                            ? attacker.damageSources().playerAttack((Player) attacker)
                            : attacker.damageSources().mobAttack(attacker);
                    causeTruesweepDamage(damageSource, damage, itemStack, attacker, entity);
                });

        if (triggerVfx) {
            attacker.level().playSound(null, attacker.getX(), attacker.getY(), attacker.getZ(),
                    SoundEvents.PLAYER_ATTACK_SWEEP, attacker.getSoundSource(), 1.0F, 1.0F);

            CastOptional.cast(attacker, Player.class).ifPresent(Player::sweepAttack);
        }
    }

    private static void causeTruesweepDamage(DamageSource damageSource, float baseDamage, ItemStack itemStack, LivingEntity attacker, LivingEntity target) {
        float targetModifier = EnchantmentHelper.getDamageBonus(itemStack, target.getMobType());
        float critMultiplier = CastOptional.cast(attacker, Player.class)
                .map(player -> ForgeHooks.getCriticalHit(player, target, false, 1.5f))
                .map(CriticalHitEvent::getDamageModifier)
                .orElse(1f);

        target.hurt(damageSource, (baseDamage + targetModifier) * critMultiplier);

        if (targetModifier > 0) {
            CastOptional.cast(attacker, Player.class).ifPresent(player -> player.magicCrit(target));
        }

        if (critMultiplier > 1) {
            attacker.getCommandSenderWorld().playSound(null, target.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT, SoundSource.PLAYERS, 1, 1.3f);
            ((Player) attacker).crit(target);
        }
    }
}